﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using LynxWiki.DomainModel;
using LynxWiki.Search;


namespace LynxWiki.Repository
{
    public class AttachmentNamespaceRepository
    {
        private IPrincipal user;
        private string nsName;

        private static string excludeDirsString = "docs|images|misc|videos";
        private static Regex excludeDirsRegEx = new Regex(excludeDirsString, RegexOptions.Compiled);

        public AttachmentNamespaceRepository()
        {
            this.nsName = "Default";
            this.user = null;
        }

        public AttachmentNamespaceRepository(string nsName, IPrincipal user = null)
        {
            this.nsName = nsName;
            this.user = user;
        }

        public string Add(string nsName, string allowUpdateUser = "", string allowUpdateRole = "", 
                            string denyReadUser = "", string denyReadRole = "")
        {
            AttachmentNamespace ns = new AttachmentNamespace(nsName, user.Identity.Name, DateTime.Now, denyReadUser, denyReadRole, allowUpdateUser, allowUpdateRole);
            //ns.Namespace = nsName;
            //if (this.user != null) {
            //    ns.Creator = this.user.Identity.Name;
            //} else {
            //    ns.Creator = string.Empty;
            //}
            DirectoryInfo dir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), ns.Namespace));
            if (!dir.Exists) {
                try {
                    dir.Create();
                    string name = Path.Combine(dir.FullName, ns.Namespace + "__namespace.xml");
                    File.WriteAllText(name, ns.ToXml(dir.FullName));
                    DirectoryInfo nsDir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), ns.Namespace, "docs"));
                    if (!nsDir.Exists) nsDir.Create();
                    DirectoryInfo nsDir1 = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), ns.Namespace, "images"));
                    if (!nsDir1.Exists) nsDir1.Create();
                    DirectoryInfo nsDir2 = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), ns.Namespace, "misc"));
                    if (!nsDir2.Exists) nsDir2.Create();
                    DirectoryInfo nsDir3 = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), ns.Namespace, "videos"));
                    if (!nsDir3.Exists) nsDir3.Create();
                    return string.Format("{0} created successfully.", nsName);
                }
                catch {
                    return string.Format("An error occurred while attempting to create {0} namespace.", nsName);
                }
            }
            return string.Format("{0} namespace already exists.", nsName);
        }

        public AttachmentNamespace GetNamespaceInfo(string nsName)
        {
            AttachmentNamespace ns = new AttachmentNamespace();
            DirectoryInfo dir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), nsName));
            if (dir.Exists) {
                FileInfo file = new FileInfo(Path.Combine(dir.FullName, nsName + "__namespace.xml"));
                if (file.Exists) {
                    ns = new AttachmentNamespace(File.ReadAllText(file.FullName));
                }
            }
            return ns;
        }

        public List<AttachmentNamespace> GetAllNamespaceNames()
        {
            List<AttachmentNamespace> lns = new List<AttachmentNamespace>();
            DirectoryInfo dir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload")));
            IEnumerable<DirectoryInfo> namespaces = dir.EnumerateDirectories();
            foreach (DirectoryInfo ns in namespaces) {
                if (!excludeDirsRegEx.IsMatch(ns.Name)) {
                    if (NamespaceExists(ns.Name)) {
                        AttachmentNamespace nspace = new AttachmentNamespace(ns.Name, null);
                        lns.Add(nspace);
                    }
                }
            }
            return lns;
        }

        public Boolean NamespaceExists(string nsName)
        {
            DirectoryInfo dir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), nsName));
            return dir.Exists;
        }

        public List<String> ListNamespaceNames()
        {
            List<AttachmentNamespace> lns = GetAllNamespaceNames();
            List<String> listNsNames = new List<String>();
            foreach (AttachmentNamespace ans in lns) {
                AttachmentNamespace an = GetNamespaceInfo(ans.Namespace);
                
                listNsNames.Add(ans.Namespace);
            }
            return listNsNames;
        }

        public Boolean NamespaceIsAccessible(string nsName, IPrincipal user, string access = "read")
        {
            AttachmentNamespace ns = new AttachmentNamespace();
            ns = this.GetNamespaceInfo(nsName);
            if (access.ToLower() == "read")
                return ns.UserReadAccess(user);
            else
                return ns.UserWriteAccess(user);
        }

        public void IndexNamespaceFiles()
        {

            DirectoryInfo dir = new DirectoryInfo(Path.Combine(HttpContext.Current.Server.MapPath("~/Attachments/upload"), this.nsName));
            if (dir.Exists) {
                List<DirectoryInfo> subdirs = dir.GetDirectories().ToList();
                foreach (DirectoryInfo sdir in subdirs) {
                    List<FileInfo> lfi = (from FileInfo file in sdir.GetFiles() where file.Name.Contains("__current.xml") select file).ToList();

                    foreach (FileInfo file in lfi) {
                        AttachmentVersion av = new AttachmentVersion(File.ReadAllText(file.FullName));
                        AttachmentSearch.AddUpdateLuceneIndex(new DomainModel.AttSearchData(av));
                    }
                }
            }
        }

    }
}
